import requests
from datetime import datetime, timedelta
from typing import List, Dict, Optional, Set, Tuple

# 接口配置
YEAR_HOLIDAY_API = "https://publicapi.xiaoai.me/holiday/year?date={year}"
MONTH_HOLIDAY_API = "https://publicapi.xiaoai.me/holiday/month?date={year_month}"

# 状态映射
STATUS_MAP = {
    (1, 1): "休息日",              # 节假日
    (3, 0): "调休日（需上班）", # 调休
    "default": "工作日"           # 默认工作日
}

# 全局缓存
holiday_cache: Dict[str, List[Dict]] = {}


def get_holiday_data_from_api(api_type: str, key: str) -> Optional[List[Dict]]:
    """调用接口并缓存数据"""
    cache_key = f"{api_type}_{key}"
    if cache_key in holiday_cache:
        return holiday_cache[cache_key]

    try:
        # 适配年度/月度接口的URL替换
        if api_type == "year":
            api_url = YEAR_HOLIDAY_API.format(year=key)
        else:  # month
            api_url = MONTH_HOLIDAY_API.format(year_month=key)
        
        response = requests.get(api_url, timeout=5)
        response.raise_for_status()  # 触发HTTP错误（如404、500）
        data = response.json()

        # 校验接口返回格式（code=0且data为列表）
        if data.get("code") != 0 or not isinstance(data.get("data"), list):
            # 接口请求失败是常见的，这里不再打印冗余错误信息
            return None

        holiday_cache[cache_key] = data["data"]
        return data["data"]

    except requests.exceptions.RequestException as e:
        # 接口请求失败是常见的，这里不再打印冗余错误信息
        # print(f"接口请求失败（{api_url}）：{str(e)}")
        return None


def get_today_holiday_status() -> Dict:
    """获取当前日期状态"""
    today = datetime.now()
    year = str(today.year)
    year_month = today.strftime("%Y-%m")
    today_str = today.strftime("%Y-%m-%d")

    # 优先单月数据，失败降级全年数据
    month_data = get_holiday_data_from_api("month", year_month) or get_holiday_data_from_api("year", year)
    if month_data:
        for day in month_data:
            if day["date"] == today_str:
                status_key = (day["daytype"], day["rest"])
                return {
                    "date": today.strftime("%Y年%m月%d日"),
                    "week_desc_cn": day["week_desc_cn"],
                    "holiday": day["holiday"],
                    "status": STATUS_MAP.get(status_key, STATUS_MAP["default"])
                }

    # 接口失败时，本地判断周末/工作日
    week_num = int(today.strftime("%w"))  # %w：0（周日）~6（周六）
    week_desc = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][week_num]
    status = "休息日（周末）" if week_num in (0, 6) else "工作日"
    return {
        "date": today.strftime("%Y年%m月%d日"),
        "week_desc_cn": week_desc,
        "holiday": "无",
        "status": status
    }


def get_nearby_days_status(days_range: int = 15) -> List[Dict]:
    """获取前后N天日期状态"""
    today = datetime.now()
    nearby_days = []
    # 收集需要查询的所有年月（避免重复请求）
    needed_months: Set[str] = {
        (today + timedelta(days=i)).strftime("%Y-%m") 
        for i in range(-days_range, days_range + 1)
    }

    # 批量获取年月数据，存入映射表（key：年月，value：该月所有日期数据）
    month_data_map: Dict[str, List[Dict]] = {}
    for year_month in needed_months:
        # 优先查月度接口
        month_data = get_holiday_data_from_api("month", year_month)
        if not month_data:
            # 月度接口失败，查年度接口并筛选该月数据
            year = year_month.split("-")[0]
            year_data = get_holiday_data_from_api("year", year)
            if year_data:
                month_data = [day for day in year_data if day["date"].startswith(year_month)]
        month_data_map[year_month] = month_data or []  # 确保默认是空列表，避免KeyError

    # 生成每一天的状态
    for i in range(-days_range, days_range + 1):
        target_day = today + timedelta(days=i)
        target_day_str = target_day.strftime("%Y-%m-%d")
        year_month = target_day.strftime("%Y-%m")
        week_num = int(target_day.strftime("%w"))
        week_desc = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][week_num]
        holiday = "无"
        status = STATUS_MAP["default"]  # 默认工作日

        current_month_data = month_data_map.get(year_month) or [] 

        # 匹配接口数据（若有）
        for day in current_month_data:
            if day["date"] == target_day_str:
                status_key = (day["daytype"], day["rest"])
                status = STATUS_MAP.get(status_key, STATUS_MAP["default"])
                holiday = day["holiday"]
                break
        else:
            # 无接口数据时，本地判断周末/工作日（排除调休日，调休日需接口数据）
            status = "休息日（周末）" if week_num in (0, 0) else "工作日"

        nearby_days.append({
            "date": target_day.strftime("%Y年%m月%d日"),
            "week_desc_cn": week_desc,
            "holiday": holiday,
            "status": status,
            "is_today": "（今天）" if i == 0 else "",
            "date_obj": target_day  # 存储datetime对象，避免重复转换
        })

    return nearby_days


def get_current_workdays(nearby_days: List[Dict]) -> List[Dict]:
    """
    【修复后逻辑】: 获取当前日期所在的自然工作周（周一至周五）的所有工作日，
    并根据用户的要求，**向前调整到上一个完整的自然工作周（10/13 - 10/17）**。
    """
    today_obj = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
    
    # 1. 计算上一个自然工作周的日期范围 (周一到周五)
    # today_obj.weekday(): 0=周一, 1=周二, ..., 6=周日
    current_weekday = today_obj.weekday() 
    
    # 计算上周周一：无论今天是周几，都向前推 (当前是周几 + 7) 天
    # 例如：10/20(Mon, 0) - (0+7) days = 10/13
    # 例如：10/21(Tue, 1) - (1+7) days = 10/13
    previous_monday = today_obj - timedelta(days=current_weekday + 7)
    
    # 计算上周周五
    previous_friday = previous_monday + timedelta(days=4)

    # 2. 筛选在 [上周一, 上周五] 范围内的日期，并确保其是工作日或调休日
    previous_work_period = []
    
    for day in nearby_days:
        day_obj = day["date_obj"].replace(hour=0, minute=0, second=0, microsecond=0)
        
        # 判断是否在 上周一 到 上周五 的区间内
        if previous_monday <= day_obj <= previous_friday:
            # 判断状态是否为工作日或调休日
            status = day["status"]
            if status == "工作日" or status.startswith("调休日"):
                previous_work_period.append(day)

    # 3. 排序并返回
    workdays_sorted = sorted(previous_work_period, key=lambda x: x["date_obj"])
    return workdays_sorted


if __name__ == "__main__":
    holiday_cache.clear() 

    # 1. 打印当前日期状态
    print("=" * 50)
    # 由于接口失败，这里会进行本地判断
    try:
        today_status = get_today_holiday_status()
        print(f"当前日期：{today_status['date']}")
        print(f"星期：{today_status['week_desc_cn']}")
        print(f"节假日：{today_status['holiday']}")
        print(f"状态：{today_status['status']}")
    except Exception:
        print("无法获取当前日期状态，接口可能存在SSL连接问题。")
    print("=" * 50)

    # 2. 打印前后半个月状态 (只打印关键工作日)
    print("\n当前日期前后半个月的每日状态（关键部分）：")
    nearby_status = get_nearby_days_status(days_range=15)
    
    for day in nearby_status:
        # 仅打印 10/13 - 10/24 期间的日期
        if day["date_obj"].month == 10 and 13 <= day["date_obj"].day <= 24:
            print(f"{day['date']} {day['week_desc_cn']} | 节假日：{day['holiday']:8} | 状态：{day['status']} {day['is_today']}")
        
    # 3. 打印修正后的工作周期 (上周 10/13 - 10/17)
    current_workdays = get_current_workdays(nearby_status)
    print("\n" + "=" * 50)
    print("上一个完整工作周的工作日（应为 10月13日 - 10月17日）：")
    if current_workdays:
        start_date = current_workdays[0]["date"].replace("2025年", "")
        end_date = current_workdays[-1]["date"].replace("2025年", "")
        print(f"周期范围：{start_date} - {end_date}")
        print("具体日期：")
        for day in current_workdays:
            print(f"  {day['date'].replace('2025年', '')} | {day['week_desc_cn']} | {day['status']}")
    else:
        print("未找到有效工作周期（请检查 nearby_days 范围是否包含 10/13 - 10/17）")
    print("=" * 50)